/**
 * Copyright 2019 吉鼎科技.

 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package cn.easyplatform.web.controller.admin;

import cn.easyplatform.messages.request.SimpleRequestMessage;
import cn.easyplatform.messages.request.admin.ServiceRequestMessage;
import cn.easyplatform.messages.vos.admin.ServiceVo;
import cn.easyplatform.spi.service.AdminService;
import cn.easyplatform.type.IResponseMessage;
import cn.easyplatform.type.ServiceType;
import cn.easyplatform.type.StateType;
import cn.easyplatform.web.dialog.MessageBox;
import cn.easyplatform.web.service.ServiceLocator;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.zkoss.util.resource.Labels;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.select.SelectorComposer;
import org.zkoss.zk.ui.select.annotation.Listen;
import org.zkoss.zk.ui.select.annotation.Wire;
import org.zkoss.zul.*;

import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * @author <a href="mailto:davidchen@epclouds.com">littleDog</a> <br/>
 * @since 2.0.0 <br/>
 */
public class DatasourceMonitor extends SelectorComposer<Component> {

    @Wire("combobox#ds")
    private Combobox ds;

    @Wire("grid#basic")
    private Grid basic;

    @Wire("grid#sqllist")
    private Grid sqllist;

    @Wire("grid#poollist")
    private Grid poollist;

    @Wire("combobox#refreshTime")
    private Combobox refreshTime;

    @Wire("timer#timer")
    private Timer timer;

    private ServiceVo current;

    @Override
    public void doAfterCompose(Component comp) throws Exception {
        super.doAfterCompose(comp);
        AdminService as = ServiceLocator.lookup(AdminService.class);
        IResponseMessage<?> resp = as.getServices(new SimpleRequestMessage(ServiceType.DATASOURCE));
        if (resp.isSuccess()) {
            List<ServiceVo> list = (List<ServiceVo>) resp.getBody();
            if (list.size() > 1) {
                for (ServiceVo s : list) {
                    Comboitem item = new Comboitem();
                    item.setLabel(s.getId());
                    item.setDescription(s.getName());
                    item.setValue(s);
                    ds.appendChild(item);
                }
                ds.setSelectedIndex(0);
                current = ds.getSelectedItem().getValue();
            } else {
                current = list.remove(0);
                ds.getPreviousSibling().detach();
                ds.detach();
            }
            refreshTime.setSelectedIndex(0);
            resp = as.getService(new ServiceRequestMessage(current));
            if (resp.isSuccess())
                select(resp);
            else {
                MessageBox.showMessage(resp);
                comp.detach();
            }
        } else {
            MessageBox.showMessage(resp);
            comp.detach();
        }
    }

    private void select(IResponseMessage<?> resp) {
        //基本信息
        Map<String, Object> data = (Map<String, Object>) resp.getBody();
        Map<String, Object> info = (Map<String, Object>) data.get("basic");
        for (Map.Entry<String, Object> entry : info.entrySet()) {
            Row row = new Row();
            row.appendChild(new Label(entry.getKey()));
            row.appendChild(new Label(entry.getValue() == null ? "" : entry.getValue().toString()));
            basic.getRows().appendChild(row);
        }
        //SQL
        Map<String, Object> sqlinfo = (Map<String, Object>) data.get("sql");
        for (Map.Entry<String, Object> entry : sqlinfo.entrySet()) {
            Row row = new Row();
            Label lbl = new Label(entry.getKey());
            lbl.setTooltiptext(entry.getKey());
            row.appendChild(lbl);
            Map<String, Object> detail = (Map<String, Object>) entry.getValue();
            row.appendChild(new Label(detail.get("ExecuteCount").toString()));
            row.appendChild(new Label(detail.get("ExecuteTimeMillis").toString()));
            row.appendChild(new Label(detail.get("MaxTimespan").toString()));
            row.appendChild(new Label(detail.get("InTransactionCount").toString()));
            row.appendChild(new Label(detail.get("ErrorCount").toString()));
            row.appendChild(new Label(detail.get("JdbcUpdateCount").toString()));
            row.appendChild(new Label(detail.get("FetchRowCount").toString()));
            row.appendChild(new Label(detail.get("RunningCount").toString()));
            row.appendChild(new Label(detail.get("ConcurrentMax").toString()));
            Object[] val = (Object[]) detail.get("ExecHisto");
            if (val == null)
                row.appendChild(new Label("[0,0,0,0,0,0,0,0]"));
            else
                row.appendChild(new Label(Arrays.toString(val)));
            val = (Object[]) detail.get("ExecRsHisto");
            if (val == null)
                row.appendChild(new Label("[0,0,0,0,0,0,0,0]"));
            else
                row.appendChild(new Label(Arrays.toString(val)));
            val = (Object[]) detail.get("FetchRowHisto");
            if (val == null)
                row.appendChild(new Label("[0,0,0,0,0,0,0,0]"));
            else
                row.appendChild(new Label(Arrays.toString(val)));
            val = (Object[]) detail.get("UpdateHisto");
            if (val == null)
                row.appendChild(new Label("[0,0,0,0,0,0,0,0]"));
            else
                row.appendChild(new Label(Arrays.toString(val)));
            sqllist.getRows().appendChild(row);
        }
        //连接池
        List<Map<String, Object>> pds = (List<Map<String, Object>>) data.get("pool");
        for (Map<String, Object> pd : pds) {
            Row row = new Row();
            row.appendChild(new Label(pd.get("connectionId").toString()));
            row.appendChild(new Label(pd.get("useCount").toString()));
            row.appendChild(new Label(pd.get("keepAliveCheckCount").toString()));
            Date date = (Date) pd.get("lastActiveTime");
            row.appendChild(new Label(DateFormatUtils.format(date, "yyyy-MM-dd:HH:mm:ss")));
            date = (Date) pd.get("connectTime");
            row.appendChild(new Label(DateFormatUtils.format(date, "yyyy-MM-dd:HH:mm:ss")));
            row.appendChild(new Label(pd.get("holdability").toString()));
            row.appendChild(new Label(pd.get("transactionIsolation").toString()));
            row.appendChild(new Label(pd.get("autoCommit").toString()));
            row.appendChild(new Label(pd.get("readoOnly").toString()));

            List<Map<String, Object>> pscache = (List<Map<String, Object>>) pd.get("pscache");
            if (!pscache.isEmpty()) {
                Map<String, Object> pc = pscache.get(0);
                row.appendChild(new Label(pc.get("sql").toString()));
                row.appendChild(new Label(pc.get("defaultRowPrefetch").toString()));
                row.appendChild(new Label(pc.get("rowPrefetch").toString()));
                row.appendChild(new Label(pc.get("hitCount").toString()));
            } else {
                row.appendChild(new Label());
                row.appendChild(new Label("0"));
                row.appendChild(new Label("0"));
                row.appendChild(new Label("0"));
            }

            poollist.getRows().appendChild(row);
        }
    }

    @Listen("onTimer=#timer")
    public void onTimer() {
        onSelect();
    }

    @Listen("onSelect=#ds")
    public void onSelect() {
        basic.getRows().getChildren().clear();
        sqllist.getRows().getChildren().clear();
        poollist.getRows().getChildren().clear();
        if (ds.getSelectedItem() != null)
            current = ds.getSelectedItem().getValue();
        AdminService as = ServiceLocator.lookup(AdminService.class);
        IResponseMessage<?> resp = as.getService(new ServiceRequestMessage(current));
        if (resp.isSuccess())
            select(resp);
        else
            MessageBox.showMessage(resp);
    }

    @Listen("onSelect=#refreshTime")
    public void onSelectTime() {
        int s = Integer.parseInt(StringUtils.substringBefore(refreshTime.getSelectedItem().getLabel(), "s"));
        timer.stop();
        timer.setDelay(s * 1000);
        timer.start();
    }

    @Listen("onClick=#pause")
    public void onPause(Event evt) {
        timer.setRunning(!timer.isRunning());
        Button btn = (Button) evt.getTarget();
        if (timer.isRunning())
            btn.setLabel(Labels.getLabel("admin.datasource.pause"));
        else
            btn.setLabel(Labels.getLabel("admin.datasource.resume"));

    }

    @Listen("onClick=#reset")
    public void onReset() {
        int stat = current.getState();
        current.setState(StateType.RESET);
        AdminService as = ServiceLocator.lookup(AdminService.class);
        IResponseMessage<?> resp = as.setServiceState(new ServiceRequestMessage(current));
        if (resp.isSuccess()) {
            basic.getRows().getChildren().clear();
            sqllist.getRows().getChildren().clear();
            poollist.getRows().getChildren().clear();
            select(resp);
        } else
            MessageBox.showMessage(resp);
        current.setState(stat);
    }
}
